package matheus.tp01cg.objetosdedesenho;

import android.graphics.Bitmap;

/**
 * Desenho de circunferencia utilizando o algoritmo de Bresenham
 * 
 * @author matheus
 * 
 */
public final class Circunferencia extends ObjetoDeDesenhoFechado {

	private Coords centro;
	private int raio;

	/**
	 * Limite maximo para recorte
	 */
	private Coords limMax;

	/**
	 * Limite minimo para recorte
	 */
	private Coords limMin;

	/**
	 * Obtem limite maximo para recorte (para uma janela de visualizacao)
	 */
	public Coords getLimMax() {
		return limMax;
	}

	/**
	 * Obtem limite minimo para recorte (para uma janela de visualizacao)
	 */
	public Coords getLimMin() {
		return limMin;
	}

	/**
	 * Define o limite maximo para ser utilizado em recorte para uma janela de
	 * visualizacao
	 * 
	 * @param limMax
	 */
	public void setLimMax(Coords limMax) {
		this.limMax = limMax;
	}

	/**
	 * Define o limite minimo para ser utilizado em recorte para uma janela de
	 * visualizacao
	 * 
	 * @param limMin
	 */
	public void setLimMin(Coords limMin) {
		this.limMin = limMin;
	}

	/**
	 * @param centro
	 *            Coordenadas para o centro da cirfunferecia
	 * @param raio
	 *            Raio da circunferencia em Pixels
	 * @param corBorda
	 * @param corPreenchimento
	 */
	public Circunferencia(Coords centro, int raio, int corBorda,
			int corPreenchimento) {
		inicializa(centro, raio, corBorda, corPreenchimento, new Coords(0, 0),
				new Coords(Integer.MAX_VALUE, Integer.MAX_VALUE));
	}

	/**
	 * 
	 * @param centro
	 *            Coordenadas para o centro da cirfunferecia
	 * @param raio
	 *            Raio da circunferencia em Pixels
	 * @param corBorda
	 * @param corPreenchimento
	 * @param limMin
	 *            Limite minimo para ser utilizado em recorte para uma janela de
	 *            visualizacao
	 * @param limMax
	 *            Limite maximo para ser utilizado em recorte para uma janela de
	 *            visualizacao
	 */
	public Circunferencia(Coords centro, int raio, int corBorda,
			int corPreenchimento, Coords limMin, Coords limMax) {
		inicializa(centro, raio, corBorda, corPreenchimento, limMin, limMax);
	}

	private void inicializa(Coords centro, int raio, int corBorda,
			int corPreenchimento, Coords limMin, Coords limMax) {
		setCentro(centro);
		setRaio(raio);
		setCorContorno(corBorda);
		setCorPreenchimento(corPreenchimento);
		setLimMin(limMin);
		setLimMax(limMax);
	}

	/**
	 * Obtem o centro da circunferencia
	 */
	@Override
	public Coords getCentro() {
		return centro;
	}

	/**
	 * Define o centro da circunferencia
	 * 
	 * @param centro
	 */
	public void setCentro(Coords centro) {
		this.centro = centro;
	}

	public int getRaio() {
		return raio;
	}

	public void setRaio(int raio) {
		this.raio = raio;
	}

	@Override
	public void desenha(Bitmap bitmap) {
		int x, y, p;
		x = 0;
		y = raio;
		p = 3 - 2 * raio;
		synchronized (bitmap) {
			plotCirclePoints(bitmap, x, y);
			while (x < y) {
				if (p < 0) {
					p += 4 * x + 6;
				} else {
					p += 4 * (x - y) + 10;
					y -= 1;
				}
				x += 1;
				plotCirclePoints(bitmap, x, y);
			}
		}
	}

	protected void bitmapSetPonto(Bitmap bitmap, int x, int y) {
		if (x >= limMin.x && y >= limMin.y && x <= limMax.x && y <= limMax.y) {
			super.bitmapSetPonto(bitmap, x, y, corContorno, espessuraBorda);
		}
	}

	private void plotCirclePoints(Bitmap bitmap, int x, int y) {
		bitmapSetPonto(bitmap, centro.x + x, centro.y + y);
		bitmapSetPonto(bitmap, centro.x - x, centro.y + y);
		bitmapSetPonto(bitmap, centro.x + x, centro.y - y);
		bitmapSetPonto(bitmap, centro.x - x, centro.y - y);
		bitmapSetPonto(bitmap, centro.x + y, centro.y + x);
		bitmapSetPonto(bitmap, centro.x - y, centro.y + x);
		bitmapSetPonto(bitmap, centro.x + y, centro.y - x);
		bitmapSetPonto(bitmap, centro.x - y, centro.y - x);
	}

	@Override
	public void rotaciona(Coords centro, double angulo) {
		this.centro.rotaciona(centro, angulo);
	}

	@Override
	public void translada(int x, int y) {
		centro.translada(x, y);
	}

	@Override
	public void escala(Coords ref, double x, double y) {
		raio = (int) Math.round((double) raio * x);
	}

	@Override
	public int getMinX() {
		return centro.x - raio;
	}

	@Override
	public int getMinY() {
		return centro.y - raio;
	}

	@Override
	public int getMaxX() {
		return centro.x + raio;
	}

	@Override
	public int getMaxY() {
		return centro.y + raio;
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		Circunferencia novaCircunferencia = new Circunferencia(
				(Coords) centro.clone(), raio, corContorno, corPreenchimento,
				(Coords) limMin.clone(), (Coords) limMax.clone());
		return (Object) novaCircunferencia;
	}

	@Override
	public boolean intercepta(Coords ponto, int raio) {
		int raioDeTeste = (int) Math.round(Math.sqrt(Math.pow(ponto.x
				- centro.x, 2)
				+ Math.pow(ponto.y - centro.y, 2)));
		return (this.raio - raio) < raioDeTeste
				&& raioDeTeste < (this.raio + raio);
	}
}
